﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MindFactorial.Dynamic
{
	public static class ObjectExtentions
	{
        internal static Dictionary<object, object> _prototype_list = new Dictionary<object, object>();
        //internal static Dictionary<DynamicContext.Group, FunctionDictionary> _context_group_list = new Dictionary<DynamicContext.Group, FunctionDictionary>();
        static Dictionary<object, FunctionDictionary> _context_list = new Dictionary<object, FunctionDictionary>();
        static Dictionary<object, DynamicStateContext> _dynamic_state_list = new Dictionary<object, DynamicStateContext>();

        #region Prototype Management
        public static void SetPrototype(this object instance, object prototype)
        {
            if (_prototype_list.ContainsKey(instance))
            {
                _prototype_list[instance] = prototype;
            }
            else
            {
                _prototype_list.Add(instance, prototype);
            }
        }
        public static object GetPrototype(this object instance)
        {
            object retval = null;
            if (_prototype_list.ContainsKey(instance))
            {
                retval = _prototype_list[instance];
            }

            return retval;
        }
        #endregion

        #region Dynamic Function Context
        public static DynamicFunctionContext<RETVAL> function<RETVAL>(this object instance, string function_name)
        {
            DynamicFunctionContext<RETVAL> ctx = null;

            if (_context_list.ContainsKey(instance))
            {
                Dictionary<string, object> temp = _context_list[instance];

                //string function_type_name = typeof(T).FullName;
                if (temp.ContainsKey(function_name))
                {
                    object context = temp[function_name];
                    if (context is DynamicFunctionContext<RETVAL>)
                        ctx = context as DynamicFunctionContext<RETVAL>;
                    else
                        throw new Exception("no function with this return type is defined");
                }
                else
                {
                    
                    ctx = new DynamicFunctionContext<RETVAL>(instance, function_name);
                    temp.Add(function_name, ctx);
                }
            }
            else
            {
                //if a context for this instance has not been created then create one
                ctx = new DynamicFunctionContext<RETVAL>(instance, function_name);
                FunctionDictionary temp = new FunctionDictionary();
                temp.Add(function_name, ctx);
                _context_list.Add(instance, temp);
            }

            return ctx;
        }
        public static DynamicFunctionContext<PARAM1,RETVAL> function<PARAM1,RETVAL>(this object instance, string function_name)
        {
            DynamicFunctionContext<PARAM1, RETVAL> ctx = null;

            if (_context_list.ContainsKey(instance))
            {
                Dictionary<string, object> temp = _context_list[instance];

                //string function_type_name = typeof(T).FullName;
                if (temp.ContainsKey(function_name))
                {
                    object context = temp[function_name];
                    if (context is DynamicFunctionContext<PARAM1, RETVAL>)
                        ctx = context as DynamicFunctionContext<PARAM1, RETVAL>;
                    else
                        throw new Exception("no function with this return type is defined");
                }
                else
                {

                    ctx = new DynamicFunctionContext<PARAM1, RETVAL>(instance, function_name);
                    temp.Add(function_name, ctx);
                }
            }
            else
            {
                //if a context for this instance has not been created then create one
                ctx = new DynamicFunctionContext<PARAM1, RETVAL>(instance, function_name);
                FunctionDictionary temp = new FunctionDictionary();
                temp.Add(function_name, ctx);
                _context_list.Add(instance, temp);
            }

            return ctx;
        }
        public static DynamicFunctionContext<PARAM1, PARAM2, RETVAL> function<PARAM1, PARAM2, RETVAL>(this object instance, string function_name)
        {
            DynamicFunctionContext<PARAM1, PARAM2, RETVAL> ctx = null;

            if (_context_list.ContainsKey(instance))
            {
                Dictionary<string, object> temp = _context_list[instance];

                //string function_type_name = typeof(T).FullName;
                if (temp.ContainsKey(function_name))
                {
                    object context = temp[function_name];
                    if (context is DynamicFunctionContext<PARAM1, PARAM2, RETVAL>)
                        ctx = context as DynamicFunctionContext<PARAM1, PARAM2, RETVAL>;
                    else
                        throw new Exception("no function with this return type is defined");
                }
                else
                {

                    ctx = new DynamicFunctionContext<PARAM1, PARAM2, RETVAL>(instance, function_name);
                    temp.Add(function_name, ctx);
                }
            }
            else
            {
                //if a context for this instance has not been created then create one
                ctx = new DynamicFunctionContext<PARAM1, PARAM2, RETVAL>(instance, function_name);
                FunctionDictionary temp = new FunctionDictionary();
                temp.Add(function_name, ctx);
                _context_list.Add(instance, temp);
            }

            return ctx;
        }
        public static DynamicFunctionContext<PARAM1, PARAM2, PARAM3, RETVAL> function<PARAM1, PARAM2, PARAM3, RETVAL>(this object instance, string function_name)
        {
            DynamicFunctionContext<PARAM1, PARAM2, PARAM3, RETVAL> ctx = null;

            if (_context_list.ContainsKey(instance))
            {
                Dictionary<string, object> temp = _context_list[instance];

                //string function_type_name = typeof(T).FullName;
                if (temp.ContainsKey(function_name))
                {
                    object context = temp[function_name];
                    if (context is DynamicFunctionContext<PARAM1, PARAM2, PARAM3, RETVAL>)
                        ctx = context as DynamicFunctionContext<PARAM1, PARAM2, PARAM3, RETVAL>;
                    else
                        throw new Exception("no function with this return type is defined");
                }
                else
                {

                    ctx = new DynamicFunctionContext<PARAM1, PARAM2, PARAM3, RETVAL>(instance, function_name);
                    temp.Add(function_name, ctx);
                }
            }
            else
            {
                //if a context for this instance has not been created then create one
                ctx = new DynamicFunctionContext<PARAM1, PARAM2, PARAM3, RETVAL>(instance, function_name);
                FunctionDictionary temp = new FunctionDictionary();
                temp.Add(function_name, ctx);
                _context_list.Add(instance, temp);
            }

            return ctx;
        }
        public static DynamicFunctionContext<PARAM1, PARAM2, PARAM3, PARAM4, RETVAL> function<PARAM1, PARAM2, PARAM3, PARAM4, RETVAL>(this object instance, string function_name)
        {
            DynamicFunctionContext<PARAM1, PARAM2, PARAM3, PARAM4, RETVAL> ctx = null;

            if (_context_list.ContainsKey(instance))
            {
                Dictionary<string, object> temp = _context_list[instance];

                //string function_type_name = typeof(T).FullName;
                if (temp.ContainsKey(function_name))
                {
                    object context = temp[function_name];
                    if (context is DynamicFunctionContext<PARAM1, PARAM2, PARAM3, PARAM4, RETVAL>)
                        ctx = context as DynamicFunctionContext<PARAM1, PARAM2, PARAM3, PARAM4, RETVAL>;
                    else
                        throw new Exception("no function with this return type is defined");
                }
                else
                {

                    ctx = new DynamicFunctionContext<PARAM1, PARAM2, PARAM3, PARAM4, RETVAL>(instance, function_name);
                    temp.Add(function_name, ctx);
                }
            }
            else
            {
                //if a context for this instance has not been created then create one
                ctx = new DynamicFunctionContext<PARAM1, PARAM2, PARAM3, PARAM4, RETVAL>(instance, function_name);
                FunctionDictionary temp = new FunctionDictionary();
                temp.Add(function_name, ctx);
                _context_list.Add(instance, temp);
            }

            return ctx;
        }
        #endregion


        #region Dynamic State Context
        public static DynamicStateContext state(this object obj)
        {
            DynamicStateContext ctx = null;
            if (_dynamic_state_list.ContainsKey(obj))
            {
                ctx = _dynamic_state_list[obj];
            }
            else
            {
                ctx = new DynamicStateContext();
                _dynamic_state_list.Add(obj, ctx);
            }
            return ctx;
        } 
        #endregion

        #region Internal Types
        public class FunctionDictionary : Dictionary<string, object> { }
        #endregion
    }

    
}
